package com.fangsheng.io.java.bio;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class SocketBIO {

    public static void main(String[] args) throws Exception {

        /**
         * 应用程序（用户线程）创建一个ServerSocket 传进一个端口9090，和一个backlog 20 为最大的连接数，在触发调用操作系统内核的时候，
         * 会把这个两个参数传给操作系统，然后操作系统返回对应的文件描述符 fd,并且绑定传进的端口，并且操作系统会创建一个listen的线程监听
         * 这个文件描述符，（ocket client = server.accept();accept一次就是一次系统调用 就是阻塞住线程【阻塞一】，等待客户端连接，连接成功才会往下走），连接成功后，
         * 内核也会clone一个socket线程又会发生一次系统调用去获取数据，如果此时pageCache数据还没有读取进来，此时也会阻塞住【阻塞二】。简而言之用户线程读取数据会通过
         * 文件描述符来读取数据，在读取数据的过程是操作系首先将磁盘的数据加载到内核的缓冲区（pageCache），然后再讲缓冲的（pageCache）的数据
         * 复制的用户空间，然后用户线程才能读取到数据，这两个过程都会备注阻塞的io模型  就是BIO [阻塞io]
         * BIO ： 的弊端，阻塞，阻塞的原因就是，每次clone出一个线程之后也会阻塞去读取数据。会有两次的一个阻塞
         */
        ServerSocket server = new ServerSocket(9090,20);

        System.out.println("step1: new ServerSocket(9090) ");

        while (true) {
            Socket client = server.accept();  //阻塞1 就是一次accept()就是一次系统调用 就是调用内核
            System.out.println("step2:client\t" + client.getPort());
            // bio 的多线程
            new Thread(new Runnable(){

                public void run() {
                    InputStream in = null;
                    try {
                        in = client.getInputStream();
                        BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                        while(true){
                            String dataline = reader.readLine(); //阻塞2 也会阻塞的，所以就放在一个新的线程中去

                            if(null != dataline){
                                System.out.println(dataline);
                            }else{
                                client.close();
                                break;
                            }
                        }
                        System.out.println("客户端断开");

                    } catch (IOException e) {
                        e.printStackTrace();
                    }

                }



            }).start();

        }
    }





}
